import unittest

from .intervals import IntervalSet


class TestIntervalSet(unittest.TestCase):
    def setUp(self):
        """每个测试前创建一个新的 IntervalSet 实例"""
        self.interval_set = IntervalSet()

    def test_empty_set(self):
        """测试空集合"""
        self.assertEqual(self.interval_set.total(), 0.0)
        self.assertEqual(len(self.interval_set.intervals), 0)

    def test_add_single_interval(self):
        """测试添加单个区间"""
        self.interval_set.add(0, 10)
        self.assertEqual(self.interval_set.total(), 10.0)
        self.assertEqual(len(self.interval_set.intervals), 1)
        self.assertIn((0, 10), self.interval_set.intervals)

    def test_add_invalid_interval(self):
        """测试添加无效区间 (l >= r)"""
        self.interval_set.add(10, 10)
        self.assertEqual(self.interval_set.total(), 0.0)
        self.interval_set.add(10, 5)
        self.assertEqual(self.interval_set.total(), 0.0)

    def test_add_non_overlapping_intervals(self):
        """测试添加不重叠的区间"""
        self.interval_set.add(0, 5)
        self.interval_set.add(10, 15)
        self.interval_set.add(20, 25)
        self.assertEqual(self.interval_set.total(), 15.0)
        self.assertEqual(len(self.interval_set.intervals), 3)

    def test_add_overlapping_intervals(self):
        """测试添加重叠区间会合并"""
        self.interval_set.add(0, 10)
        self.interval_set.add(5, 15)
        self.assertEqual(self.interval_set.total(), 15.0)
        self.assertEqual(len(self.interval_set.intervals), 1)
        self.assertIn((0, 15), self.interval_set.intervals)

    def test_add_adjacent_intervals(self):
        """测试添加相邻区间会合并"""
        self.interval_set.add(0, 10)
        self.interval_set.add(10, 20)
        self.assertEqual(self.interval_set.total(), 20.0)
        self.assertEqual(len(self.interval_set.intervals), 1)
        self.assertIn((0, 20), self.interval_set.intervals)

    def test_add_contained_interval(self):
        """测试添加被包含的区间"""
        self.interval_set.add(0, 20)
        self.interval_set.add(5, 15)
        self.assertEqual(self.interval_set.total(), 20.0)
        self.assertEqual(len(self.interval_set.intervals), 1)
        self.assertIn((0, 20), self.interval_set.intervals)

    def test_add_containing_interval(self):
        """测试添加包含现有区间的区间"""
        self.interval_set.add(5, 15)
        self.interval_set.add(0, 20)
        self.assertEqual(self.interval_set.total(), 20.0)
        self.assertEqual(len(self.interval_set.intervals), 1)
        self.assertIn((0, 20), self.interval_set.intervals)

    def test_add_multiple_overlapping_intervals(self):
        """测试添加多个重叠区间"""
        self.interval_set.add(0, 5)
        self.interval_set.add(10, 15)
        self.interval_set.add(20, 25)
        self.interval_set.add(3, 22)  # 合并前三个区间
        self.assertEqual(self.interval_set.total(), 25.0)
        self.assertEqual(len(self.interval_set.intervals), 1)
        self.assertIn((0, 25), self.interval_set.intervals)

    def test_remove_from_empty(self):
        """测试从空集合移除区间"""
        self.interval_set.remove(0, 10)
        self.assertEqual(self.interval_set.total(), 0.0)

    def test_remove_invalid_interval(self):
        """测试移除无效区间"""
        self.interval_set.add(0, 10)
        self.interval_set.remove(5, 5)
        self.assertEqual(self.interval_set.total(), 10.0)

    def test_remove_entire_interval(self):
        """测试移除整个区间"""
        self.interval_set.add(0, 10)
        self.interval_set.remove(0, 10)
        self.assertEqual(self.interval_set.total(), 0.0)
        self.assertEqual(len(self.interval_set.intervals), 0)

    def test_remove_left_part(self):
        """测试移除区间的左侧部分"""
        self.interval_set.add(0, 10)
        self.interval_set.remove(0, 5)
        self.assertEqual(self.interval_set.total(), 5.0)
        self.assertIn((5, 10), self.interval_set.intervals)

    def test_remove_right_part(self):
        """测试移除区间的右侧部分"""
        self.interval_set.add(0, 10)
        self.interval_set.remove(5, 10)
        self.assertEqual(self.interval_set.total(), 5.0)
        self.assertIn((0, 5), self.interval_set.intervals)

    def test_remove_middle_part(self):
        """测试移除区间的中间部分（分裂）"""
        self.interval_set.add(0, 10)
        self.interval_set.remove(3, 7)
        self.assertEqual(self.interval_set.total(), 6.0)
        self.assertEqual(len(self.interval_set.intervals), 2)
        self.assertIn((0, 3), self.interval_set.intervals)
        self.assertIn((7, 10), self.interval_set.intervals)

    def test_remove_multiple_intervals(self):
        """测试移除跨越多个区间"""
        self.interval_set.add(0, 5)
        self.interval_set.add(10, 15)
        self.interval_set.add(20, 25)
        self.interval_set.remove(3, 22)
        self.assertEqual(self.interval_set.total(), 6.0)
        self.assertEqual(len(self.interval_set.intervals), 2)
        self.assertIn((0, 3), self.interval_set.intervals)
        self.assertIn((22, 25), self.interval_set.intervals)

    def test_contains_empty_interval(self):
        """测试包含空区间（应返回 True）"""
        self.assertTrue(self.interval_set.contains(5, 5))

    def test_contains_full_coverage(self):
        """测试完全覆盖的区间"""
        self.interval_set.add(0, 10)
        self.assertTrue(self.interval_set.contains(0, 10))
        self.assertTrue(self.interval_set.contains(2, 8))
        self.assertTrue(self.interval_set.contains(0, 5))
        self.assertTrue(self.interval_set.contains(5, 10))

    def test_contains_no_coverage(self):
        """测试未覆盖的区间"""
        self.interval_set.add(0, 10)
        self.assertFalse(self.interval_set.contains(10, 15))
        self.assertFalse(self.interval_set.contains(15, 20))

    def test_contains_partial_coverage(self):
        """测试部分覆盖的区间"""
        self.interval_set.add(0, 10)
        self.assertFalse(self.interval_set.contains(5, 15))
        self.assertFalse(self.interval_set.contains(-5, 5))

    def test_contains_multiple_intervals(self):
        """测试多个区间的覆盖"""
        self.interval_set.add(0, 5)
        self.interval_set.add(5, 10)
        self.assertTrue(self.interval_set.contains(0, 10))
        self.assertTrue(self.interval_set.contains(3, 7))

    def test_contains_gap_in_intervals(self):
        """测试有间隙的区间"""
        self.interval_set.add(0, 5)
        self.interval_set.add(10, 15)
        self.assertFalse(self.interval_set.contains(0, 15))
        self.assertFalse(self.interval_set.contains(3, 12))
        self.assertTrue(self.interval_set.contains(0, 5))
        self.assertTrue(self.interval_set.contains(10, 15))

    def test_difference_empty_set(self):
        """测试空集合的差集"""
        diff = self.interval_set.difference(0, 10)
        self.assertEqual(diff, [(0, 10)])

    def test_difference_invalid_interval(self):
        """测试无效区间的差集"""
        diff = self.interval_set.difference(10, 10)
        self.assertEqual(diff, [])

    def test_difference_full_coverage(self):
        """测试完全覆盖的差集"""
        self.interval_set.add(0, 10)
        diff = self.interval_set.difference(0, 10)
        self.assertEqual(diff, [])
        diff = self.interval_set.difference(2, 8)
        self.assertEqual(diff, [])

    def test_difference_no_coverage(self):
        """测试无覆盖的差集"""
        self.interval_set.add(20, 30)
        diff = self.interval_set.difference(0, 10)
        self.assertEqual(diff, [(0, 10)])

    def test_difference_partial_coverage(self):
        """测试部分覆盖的差集"""
        self.interval_set.add(5, 15)
        diff = self.interval_set.difference(0, 10)
        self.assertEqual(diff, [(0, 5)])

        self.interval_set = IntervalSet()
        self.interval_set.add(0, 5)
        diff = self.interval_set.difference(0, 10)
        self.assertEqual(diff, [(5, 10)])

    def test_difference_gap_in_intervals(self):
        """测试有间隙的差集"""
        self.interval_set.add(0, 5)
        self.interval_set.add(10, 15)
        diff = self.interval_set.difference(0, 15)
        self.assertEqual(diff, [(5, 10)])

    def test_difference_multiple_gaps(self):
        """测试多个间隙的差集"""
        self.interval_set.add(0, 5)
        self.interval_set.add(10, 15)
        self.interval_set.add(20, 25)
        diff = self.interval_set.difference(0, 30)
        self.assertEqual(diff, [(5, 10), (15, 20), (25, 30)])

    def test_float_intervals(self):
        """测试浮点数区间"""
        self.interval_set.add(0.5, 10.5)
        self.interval_set.add(5.5, 15.5)
        self.assertEqual(self.interval_set.total(), 15.0)
        self.assertTrue(self.interval_set.contains(1.0, 10.0))

    def test_complex_operations_sequence(self):
        """测试复杂的操作序列"""
        # 添加多个区间
        self.interval_set.add(0, 10)
        self.interval_set.add(20, 30)
        self.interval_set.add(40, 50)
        self.assertEqual(self.interval_set.total(), 30.0)

        # 移除部分
        self.interval_set.remove(5, 25)
        self.assertEqual(self.interval_set.total(), 20.0)
        self.assertIn((0, 5), self.interval_set.intervals)
        self.assertIn((25, 30), self.interval_set.intervals)
        self.assertIn((40, 50), self.interval_set.intervals)

        # 添加合并区间
        self.interval_set.add(3, 45)
        self.assertEqual(self.interval_set.total(), 50.0)
        self.assertEqual(len(self.interval_set.intervals), 1)
        self.assertIn((0, 50), self.interval_set.intervals)

    def test_repr(self):
        """测试字符串表示"""
        self.interval_set.add(0, 10)
        self.interval_set.add(20, 30)
        repr_str = repr(self.interval_set)
        self.assertIn("IntervalSet", repr_str)
        self.assertIn("total=20", repr_str)


if __name__ == '__main__':
    unittest.main()
